package org.example.rabbitmq.provider.mq;

import org.example.rabbitmq.provider.notify.QueueCreatedNotifier;
import org.example.rabbitmq.provider.repository.QueueRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * RabbitMq队列管理帮助类
 */
@Component
public class RabbitMqManager {
    Logger logger = LoggerFactory.getLogger(RabbitMqManager.class);
    public static final String EXCHANGE_NAME = "data-sync-exchange";
    // 一个应用实例内一份，避免频繁反复创建Queue
    private static Map<String, String> queuesInThisAppInstance = new ConcurrentHashMap<String, String>();
    @Autowired
    RabbitAdmin rabbitAdmin;
    @Autowired
    QueueRepository queueRepository;
    @Autowired
    QueueCreatedNotifier notifier;

    public String createQueueName(String tenantId) {
        return "data-sync-queue-" + tenantId;
    }

    public String createRoutingKey(String tenantId) {
        return "data-sync-" + tenantId;
    }

    public void createQueueIfAbsent(String queueName, String routingKey) {
        logger.info("dynamic queue creating, queue: " + queueName);
        // queue可以反复创建，但是没有必要每次发送都创建
        if (queuesInThisAppInstance.containsKey(queueName)) {
            logger.info("queue already exists, queue: " + queueName);
            return;
        }
        createQueue(queueName);
        bindingWithExchange(EXCHANGE_NAME, queueName, routingKey);
        // 存储到Redis
        queueRepository.add(queueName);
        // 发送Queue创建消息，可能原因：新增租户
        notifier.broadcast(queueName);
        // 存储到本地
        queuesInThisAppInstance.put(queueName, routingKey);
        logger.info("dynamic queue created, queue: " + queueName);
    }

    /**
     * 创建队列
     *
     * @param queueName 队列名称
     */
    public void createQueue(String queueName) {
        rabbitAdmin.declareQueue(new Queue(queueName, true));
    }

    /**
     * 绑定队列
     *
     * @param exchangeName 路由器名称
     * @param queueName    队列名称
     * @param routingKey   路由键
     */
    private void bindingWithExchange(String exchangeName, String queueName, String routingKey) {
        rabbitAdmin.declareBinding(new Binding(queueName, Binding.DestinationType.QUEUE, exchangeName, routingKey, null));
    }
}